﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace Apps.Common
{
    public static class EnumMvcHelper
    {
        public static Dictionary<Type, string> GridFormaterFuncCache = new Dictionary<Type, string>();
        public static Dictionary<Type, Dictionary<int, string>> EnumCache = new Dictionary<Type, Dictionary<int, string>>();
        public static Dictionary<int, string> GetEnumHash<T>()
        {
            Type type = typeof(T);
            if (!EnumCache.ContainsKey(type))
            { 
                Dictionary<int, string> ret = new Dictionary<int, string>();
                MemberInfo[] memInfolist = type.GetMembers(BindingFlags.Static | BindingFlags.Public);
                FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public);

                StringBuilder retFunc = new StringBuilder("function {0}(val) {\n");
                retFunc.Append("switch(parseInt(val)){\n");
                foreach (var memInfo in memInfolist)
                {
                    object[] attrs = memInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    if (null != attrs && attrs.Length > 0)
                    {
                        ret.Add((int)Enum.Parse(type, memInfo.Name), ((DescriptionAttribute)attrs[0]).Description);
                    }
                }
                EnumCache.Add(type, ret);
            }
            return EnumCache[type];
        }
        /// <summary>
        /// 获取枚举类型的描述
        /// </summary>
        /// <param name="functionName">Javascript方法名</param>
        /// <returns></returns>
        public static string GridFormatterFunc<T>(string functionName="")
        {
            if (!typeof(T).IsEnum)
            {
                throw new Exception("传入的泛型参数必须为枚举类型！");
            }
            Type type = typeof(T);
            if (!GridFormaterFuncCache.ContainsKey(type))
            {
                MemberInfo[] memInfolist = type.GetMembers(BindingFlags.Static | BindingFlags.Public);
                FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public);

                StringBuilder retFunc = new StringBuilder("function {0}(val) {\n");
                retFunc.Append("switch(parseInt(val)){\n");
                foreach (var memInfo in memInfolist)
                {
                    object[] attrs = memInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    if (null != attrs && attrs.Length > 0)
                    {
                        retFunc.Append(" case ")
                            .Append(((int)Enum.Parse(type, memInfo.Name)).ToString())
                            .Append(":\n")
                            .Append(" return '").Append(((DescriptionAttribute)attrs[0]).Description).Append("';\n");
                    }
                }
                retFunc.Append("}\n")
                    .Append("return '';");
                GridFormaterFuncCache.Add(type, retFunc.Append("}").ToString());
            }
            return GridFormaterFuncCache[type].Replace("{0}", functionName);
        }

        #region 下拉选择框
        public static List<EnumItem> GetEnumAllDesc<T>(bool HasEmptyItem=false)
        {
            if (typeof(T).BaseType != typeof(Enum))
                throw new Exception("传入的泛型参数必须为枚举类型！");

            List<EnumItem> dic = new List<EnumItem>();
            Array arr = System.Enum.GetValues(typeof(T));    // 获取枚举的所有值
            if(HasEmptyItem)
            {
                EnumItem item = new EnumItem();
                item.Key = -1;
                item.Desc = "--请选择--";

                dic.Add(item);
            }
            foreach (var a in arr)
            {
                EnumItem item = new EnumItem();
                item.Key = (int)a;
                item.Desc = GetEnumDesc(typeof(T), a);

                dic.Add(item);
            }
            return dic;
        }

        public static List<EnumItem> GetEnumAllDesc<T>(string seltext)
        {
            if (typeof(T).BaseType != typeof(Enum))
                throw new Exception("传入的泛型参数必须为枚举类型！");

            List<EnumItem> dic = new List<EnumItem>();
            Array arr = System.Enum.GetValues(typeof(T));    // 获取枚举的所有值
            dic.Add(new EnumItem() { Key = -1, Desc = seltext });
            foreach (var a in arr)
            {
                EnumItem item = new EnumItem();
                item.Key = (int)a;
                item.Desc = GetEnumDesc(typeof(T), a);

                dic.Add(item);
            }
           
            return dic;
        }

        public static System.Web.Mvc.SelectList GetMVCSelectList<T>(string DefaultName)
        {
            if (!typeof(T).IsEnum)
            {
                throw new Exception("传入的泛型参数必须为枚举类型！");
            }
            var List = EnumMvcHelper.GetEnumAllDesc<T>();
            if (!string.IsNullOrEmpty(DefaultName))
            {
                List.Insert(0, new Common.EnumItem { Key = -1, Desc = DefaultName });
            }
            return new System.Web.Mvc.SelectList(List, "Key", "Desc");
        }

        private static string GetEnumDesc(Type e, object t)
        {
            FieldInfo EnumInfo = e.GetField(t.ToString());
            DescriptionAttribute[] EnumAttributes = (DescriptionAttribute[])EnumInfo.
                GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (EnumAttributes.Length > 0)
            {
                return EnumAttributes[0].Description;
            }
            return e.ToString();
        }
        public static string GetEnumDesc<T>(object value)
        {
            if (value.GetType() == typeof(DBNull) || string.IsNullOrEmpty(value.ToString()))
                return "";
            if (!typeof(T).IsEnum)
            {
                throw new Exception("传入的泛型参数必须为枚举类型！");
            }
            T t = (T)Enum.ToObject(typeof(T), Convert.ToInt32(value));
            FieldInfo EnumInfo = typeof(T).GetField(t.ToString());
            if (EnumInfo != null)
            {
                DescriptionAttribute[] EnumAttributes = (DescriptionAttribute[])EnumInfo.
                   GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (EnumAttributes.Length > 0)
                {
                    return EnumAttributes[0].Description;
                }
                return t.ToString();
            }
            else//没有此项
            {
                return value.ToString();
            }
        }

        /// <summary>
        /// 获取字段Description
        /// </summary>
        /// <param name="fieldInfo">FieldInfo</param>
        /// <returns>DescriptionAttribute[] </returns>
        public static DescriptionAttribute[] GetDescriptAttr(FieldInfo fieldInfo)
        {
            if (fieldInfo != null)
            {
                return (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
            }
            return null;
        }


        /// <summary>
        /// 根据Description获取枚举
        /// 说明：
        /// 单元测试-->通过
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="description">枚举描述</param>
        /// <returns>枚举</returns>
        public static T GetEnumName<T>(string description)
        {
            if (!typeof(T).IsEnum)
            {
                throw new Exception("传入的泛型参数必须为枚举类型！");
            }
            Type _type = typeof(T);
            foreach (FieldInfo field in _type.GetFields())
            {
                DescriptionAttribute[] _curDesc = GetDescriptAttr(field);
                if (_curDesc != null && _curDesc.Length > 0)
                {
                    if (_curDesc[0].Description == description)
                        return (T)field.GetValue(null);
                }
                else
                {
                    if (field.Name == description)
                        return (T)field.GetValue(null);
                }
            }
            throw new ArgumentException(string.Format("{0} 未能找到对应的枚举.", description), "Description");
        }

        /// <summary>  
        /// 根据枚举类型得到其所有的 值 与 枚举定义Description属性 的集合  
        /// </summary>  
        /// <param name="enumType"></param>  
        /// <returns></returns>  
        public static Dictionary<string, string> GetNVCFromEnumValue(Type enumType)
        {
            Dictionary<string, string> nvc = new Dictionary<string, string>();
            Type typeDescription = typeof(DescriptionAttribute);
            System.Reflection.FieldInfo[] fields = enumType.GetFields();
            string strText = string.Empty;
            string strValue = string.Empty;
            foreach (FieldInfo field in fields)
            {
                if (field.FieldType.IsEnum)
                {
                    strValue = ((int)enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null)).ToString();
                    object[] arr = field.GetCustomAttributes(typeDescription, true);
                    if (arr.Length > 0)
                    {
                        DescriptionAttribute aa = (DescriptionAttribute)arr[0];
                        strText = aa.Description;
                    }
                    else
                    {
                        strText = "";
                    }
                    nvc.Add(strText, strValue);
                }
            }
            return nvc;
        }
        #endregion

        #region MVC扩展

        public static MvcHtmlString DropDownList<T>(this HtmlHelper htmlHelper, string controlName, string defaultName)
        {
            if (!typeof(T).IsEnum)
            {
                throw new Exception("泛型类型错误，必须是有个效的枚举类型");
            }
            var List = EnumMvcHelper.GetEnumAllDesc<T>();
            if (!string.IsNullOrEmpty(defaultName))
            {
                List.Insert(0, new Common.EnumItem { Key = -1, Desc = defaultName });
            }
            return htmlHelper.DropDownList(controlName, new System.Web.Mvc.SelectList(List, "Key", "Desc"));
        }
        #endregion
    }
}
